#pragma once

#include <iostream>
#include <vector>
#include <semaphore.h>
#include "Sem.hpp"
#include "Mutex.hpp"
using namespace SemModule;
using namespace LockModule;
namespace RingBufferModule
{
    template <class T>
    class RingBuffer
    {
    public:
        RingBuffer(int cap) : _cap(cap), _ring(cap), _p_step(0), _c_step(0), _datasem(0), _spacesem(cap) // 初始化容量和位置
        {
            // int n = ::sem_init(&_datasem, 0, 0); // 初始值为0
            // (void)n;
            // int m = ::sem_init(&_spacesem, 0, _cap); // 初始值为容量大小
            // (void)m;
        }
        //为什么没有判断？信号量，本身就是表示资源数目的，只要成功，就一定有，不需要判断 
        void Equeue(const T &in)
        {
            // 生产者
            _spacesem.P();//申请空间资源，即空间信号量--,如果信号量是0，就会阻塞住
            LockGuard lockguard(_p_lock);//先申请信号量，后加锁
            _ring[_p_step] = in; // 生产完毕
            _p_step++;
            _p_step %= _cap;    //维持环形特性
            _datasem.V();//数据信号量++
        }
        void Pop(T *out)
        {
            // 消费者
            _datasem.P();//申请数据资源，即数据信号量--
            LockGuard lockguard(_c_lock);
            *out = _ring[_c_step];
            _c_step++;
            _c_step %= _cap;
            _spacesem.V();
        }
        ~RingBuffer()
        {
            
        }

    private:
        std::vector<T> _ring; // 环
        int _cap;             // 总容量
        int _p_step;          // 生产者位置
        int _c_step;          // 消费者位置

        Sem _datasem;  // 数据信号量
        Sem _spacesem; // 空间信号量

        Mutex _p_lcok;//生产者锁
        Mutex _c_lock;//消费者锁
    };
}